package co.edu.javeriana.monopoly.server.modelo;


import co.edu.javeriana.fw.comunicacion.AddressMachine;
import co.edu.javeriana.fw.comunicacion.IServicios;
import co.edu.javeriana.fw.comunicacion.Peer;
import co.edu.javeriana.monopoly.server.eventos.AdicionarJugador;
import co.edu.javeriana.monopoly.server.eventos.IniciarContador;

import java.io.IOException;

import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;

public class Monopoly extends Peer{
    private static Monopoly instance = null;
    
    
    public static Monopoly getMonopoly() throws RemoteException {
        if (instance == null ){
            instance = new Monopoly();
        }
        return instance;
    }
    private Monopoly() throws RemoteException {
        super();
    }
    private int maxJugadores;
    private int maxcasas;
    private int maxedificios;
    private int dinerojugadores;
    private long tiempoespera;
    private boolean closed = false;
    
    private int jugadores = 0;
    
    private Tablero tablero;
    private List<Jugada> jugadas;
    private Jugada ultimaJugada;
    private Hashtable<Integer,String> posjugadores = new Hashtable<Integer,String>();
    private int turno = 1;

    public void setTablero(Tablero tablero) {
        this.tablero = tablero;
    }

    public Tablero getTablero() {
        return tablero;
    }

    public void setJugadas(List<Jugada> jugadas) {
        this.jugadas = jugadas;
    }

    public List<Jugada> getJugadas() {
        return jugadas;
    }

    public void setUltimaJugada(Jugada ultimaJugada) {
        this.ultimaJugada = ultimaJugada;
    }

    public Jugada getUltimaJugada() {
        return ultimaJugada;
    }
    
    public Properties loadParams(String file)
        throws IOException {

      // Loads a ResourceBundle and creates Properties from it
      Properties     prop   = new Properties();
      
      ResourceBundle bundle = ResourceBundle.getBundle(file, Locale.getDefault());

      // Retrieve the keys and populate the properties object
      Enumeration enume = bundle.getKeys();
      String      key  = null;
      while (enume.hasMoreElements()) {
        key = (String) enume.nextElement();

        prop.put(key, bundle.getObject(key));
      }

      return prop;
    }

    public void loadProperties() throws Exception{
        
        Properties conprops = null;

        try{
            conprops = loadParams("Monopoly");
            this.setMaxJugadores(Integer.parseInt(conprops.getProperty("monopoly.players")));
            this.setMaxcasas(Integer.parseInt(conprops.getProperty("monopoly.maxcasas")));
            this.setMaxedificios(Integer.parseInt(conprops.getProperty("monopoly.maxedificios")));
            this.setDinerojugadores(Integer.parseInt(conprops.getProperty("monopoly.dinero")));
            this.setTiempoespera(Integer.parseInt(conprops.getProperty("monopoly.tiempoespera")));
            AddressMachine m = new AddressMachine();
            m.setNameMachine(conprops.getProperty("monopoly.host"));
            m.setIp(conprops.getProperty("monopoly.ip"));
            m.setPortToRecieveRMI(Integer.parseInt(conprops.getProperty("monopoly.portrmi")));
            this.setMyAddressMachine(m);            

        }catch (Exception ex) {
          ex.printStackTrace();
          throw ex;
        } finally {
          // Clear properties
          conprops.clear();
          conprops = null;
        }

    }
    public void iniciarJuego() throws MonopolyException {
        try {
            loadProperties();
            tablero = new Tablero();
        } catch (Exception e) {
            e.printStackTrace();
            throw new MonopolyException("Error a l iniciar los parametros de juego",e);
        }
    }
    public void setMaxJugadores(int maxJugadores) {
        this.maxJugadores = maxJugadores;
    }

    public int getMaxJugadores() {
        return maxJugadores;
    }

    public void setMaxcasas(int maxcasas) {
        this.maxcasas = maxcasas;
    }

    public int getMaxcasas() {
        return maxcasas;
    }

    public void setMaxedificios(int maxedificios) {
        this.maxedificios = maxedificios;
    }

    public int getMaxedificios() {
        return maxedificios;
    }

    public void setDinerojugadores(int dinerojugadores) {
        this.dinerojugadores = dinerojugadores;
    }

    public int getDinerojugadores() {
        return dinerojugadores;
    }

    public void setJugadores(int jugadores) {
        this.jugadores = jugadores;
    }

    public int getJugadores() {
        return jugadores;
    }
    
    public void adicionarJugador(Jugador j) throws MonopolyException {
        if ( getJugadores() < getMaxJugadores() ){
            setJugadores(getJugadores()+1);
            j.setPosicion(getJugadores());
            j.setId(getJugadores());
            j.setColor(Color.getColor(j.getPosicion()));
            posjugadores.put(new Integer(j.getPosicion()), j.getNombre());
            getTablero().getJugadores().put(j.getNombre(),j);
        }else{
            throw new MonopolyException("Excede el numero maximo de jugadores",null);
        }
    }
    
    private int turnoSiguiente(){
        turno++;
        if (turno > maxJugadores){
            turno = 1;
        }
        return turno;
    }
    
    public Object recibirEvento(Object jugada) throws RemoteException {
        try {
            return (Jugada)recibirEvento((Jugada)jugada);
        }catch (MonopolyException me) {
            me.printStackTrace();
            throw new RemoteException("",me);
        }
    }

    public Jugada recibirEvento(Jugada jugada) throws RemoteException, MonopolyException{
        try {
            jugada.getRegla().setJugada(jugada);
            jugada.getRegla().ejecutar();
        } catch (MonopolyException e) {
            e.printStackTrace();
            throw e;
        }
        return new Jugada();
    }
    
    public void enviarNotificacion(Object jugada, List jugadores) throws RemoteException {
        enviarNotificacion((Jugada)jugada, jugadores);
    }

    public void enviarNotificacion(Object jugada, Object jugador) throws RemoteException {
        enviarNotificacion((Jugada)jugada, (Jugador)jugador);
    }

    public void enviarNotificacion(Object jugada) throws RemoteException {
        enviarNotificacion((Jugada)jugada);
    }

    public void enviarNotificacion(Jugada jugada, List jugadores) throws RemoteException{
        System.out.println("Envia Notificacion");
    }
    public void enviarNotificacion(Jugada jugada, Jugador jugador) throws RemoteException{
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }
        try {
            String name = "rmi://"+jugador.getMachine().getNameMachine()+":"+jugador.getMachine().getPortToRecieveRMI()+"/IServicios";
            IServicios servicio = (IServicios) Naming.lookup(name);
            servicio.recibirEvento(jugada);
        } catch (Exception e) {         
            System.err.println("ComputePi exception: " + e.getMessage());
            e.printStackTrace();
        }
        
        System.out.println("Envia Notificacion");
    }
    public void enviarNotificacion(Jugada jugada) throws RemoteException{
        System.out.println("Envia Notificacion");
    }
    

    public static void main(String[] args){
        Monopoly juego;

        try {
            juego = Monopoly.getMonopoly();
            juego.iniciarJuego();
            
            if (System.getSecurityManager() == null) {
                System.setSecurityManager(new RMISecurityManager());                        
            }
             String name = "//"+juego.getMyAddressMachine().getNameMachine()+":"+juego.getMyAddressMachine().getPortToRecieveRMI()+"/IServicios";   
             try {
                Naming.rebind(name, juego);
                System.out.println("bounded");
                IniciarContador contador = new IniciarContador(juego);
                Thread t;
                t = new Thread(contador);
                t.start();
                
            } catch (Exception e) {
                System.err.println("ComputeEngine exception: " +  e.getMessage());
                e.printStackTrace();
            }
            
        } catch (MonopolyException e) {
            e.printStackTrace();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    public void setTiempoespera(long tiempoespera) {
        this.tiempoespera = tiempoespera;
    }

    public long getTiempoespera() {
        return tiempoespera;
    }

    public void setPosjugadores(Hashtable<Integer, String> posjugadores) {
        this.posjugadores = posjugadores;
    }

    public Hashtable<Integer, String> getPosjugadores() {
        return posjugadores;
    }

    public void setClosed(boolean closed) {
        this.closed = closed;
    }

    public boolean isClosed() {
        return closed;
    }

    public void setTurno(int turno) {
        this.turno = turno;
    }

    public int getTurno() {
        return turno;
    }
}
